﻿using IGS.Core.Evaluators;
using IGS.Core.Integrators;
using IGS.Core.Logging;
using IGS.Core.Systems;

namespace IGS.Core
{
    public class Simulator
    {
        private readonly INBodySystem Bodies;
        private readonly IForceEvaluator ForceEvaluator;
        private readonly IIntegrator Integrator;
        private readonly ILogger Logger;

        public Simulator(INBodySystem bodies, IForceEvaluator forceEvaluator, IIntegrator integrator, ILogger logger)
        {
            Bodies = bodies;
            ForceEvaluator = forceEvaluator;
            Integrator = integrator;
            Logger = logger;

            Reset();
            ForceEvaluator.Evaluate(Bodies);
            EndStep();
        }

        public void Evolve(double dt)
        {
            Logger.LogInfo("Begin Integration");

            Integrator.Predict(Bodies, dt);
            Reset();
            ForceEvaluator.Evaluate(Bodies);
            Integrator.Correct(Bodies, dt);
            EndStep();

            Logger.LogInfo("Kinetic Energy = {0:0.000}", Bodies.KineticEnergy);
            Logger.LogInfo("Potential Energy = {0:0.000}", Bodies.PotentialEnergy);

            foreach (var body in Bodies)
                Logger.LogInfo(body.ToString());

            Logger.LogInfo("End Integration");
        }

        private void Reset()
        {
            foreach (var body in Bodies)
                body.Reset();
        }
        
        private void EndStep()
        {
            foreach (var body in Bodies)
                body.EndStep();
        }
    }
}